package com.link.base.base.user.service;

import com.alibaba.fastjson.JSONObject;
import com.link.base.base.user.model.User;
import com.link.base.base.user.model.RespDTO;
import com.link.base.base.user.model.ThirdLogin;
import com.link.base.base.user.model.ThirdLoginDTO;
import com.link.core.basic.service.BasicService;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.util.RedisUtil;
import com.link.core.util.StringUtils;
import com.link.core.util.redisclient.LinkRedisClient;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

/**
 * QQ && 微信登录
 *
 * @author 曲元涛
 * @date 2019/03/29 17:19
 */
public interface ThirdLoginService extends BasicService<ThirdLogin> {

    String ENCODE = "UTF-8";

    Long CORP_ID = 0L;

    String PLATFORM_QQ = "QQ";

    String PLATFORM_WX = "WX";

    Integer EXPIRE_TIME = 120;

    Integer TEN_MINUTES = 600;

    String PC_CRM = "CRM";

    String PC_DMS = "DMS";

    String PC_STORE = "STORE";

    String APP_MARKETING = "marketing";

    String APP_DMS = "dms";

    Integer VALID_ACCESS_CODE = 0;

    String ERR_CODE = "errcode";

    String ERR_MSG = "errmsg";

    String Y_STR = "Y";

    /**
     * 字符串非空校验
     *
     * @author 曲元涛
     * @date 2020/7/10 11:49
     * @param reference     待校验字符串
     * @param errorMessage  校验不通过提示信息
     */
    default String notBlank(String reference, String errorMessage) {
        if (StringUtils.isBlank(reference)) {
            throw new IllegalArgumentException(errorMessage);
        }
        return reference;
    }

    /**
     * 获取哈希值，如果需要的话删除该哈希
     *
     * @author 曲元涛
     * @date 2020/7/10 11:54
     * @param key   哈希
     * @param field 字段名
     * @param del   是否删除
     */
    default String hGetAfterDelIfNecessary(String key, String field, boolean... del) {
        LinkRedisClient j = null;
        try {
            j = RedisUtil.getJedis();
            String val = j.hget(key, field);
            if (del.length > 0 && del[0]) {
                j.del(key);
            }
            return val;
        } finally {
            RedisUtil.returnResource(j);
        }
    }

    /**
     * 设置字符串缓存，过期时间可选
     *
     * @author 曲元涛
     * @date 2020/7/10 13:04
     * @param key K
     * @param val V
     * @param seconds 过期时间
     */
    default void setAndExpiredOptional(String key, String val, int... seconds) {
        LinkRedisClient j = null;
        try {
            j = RedisUtil.getJedis();
            if (seconds.length > 0 && seconds[0] > 0) {
                // key不存在时，设置k,v，过期时间单位是秒
                j.set(key, val, "nx", "ex", seconds[0]);
            } else {
                // 设置 k,v 永不过期
                j.set(key, val);
            }
        } finally {
            RedisUtil.returnResource(j);
        }
    }

    enum AuthUrlParam {
        /**认证URL前缀*/
        AUTH_URL_PREFIX,
        /**Web appId*/
        WEB_APP_ID,
        /**随机字符串，用于安全验证*/
        STATE,
        /**回调接口URI*/
        REDIRECT_URI;
    }

    /**
     * QQ\微信登录接口（无需密码，根据绑定信息登录）
     *
     * @author cuizhiyong
     * @param dto 接收platformType(平台类型),username(登录用户名),token(认证信息key)
     * @date 2019/4/3
     */
    public RespDTO login(ThirdLoginDTO dto, HttpServletRequest request) throws Exception;

    /**
     * 获取微信授权URL
     *
     * @author quyuantao
     * @date 2019/4/2 20:02
     * @param thirdLoginDTO state字段用来区分个人中心|登录页
     */
    String getWeChatAuthUrl(ThirdLoginDTO thirdLoginDTO);

    /**
     * 获取QQ授权CODE的URL地址
     *
     * @author cuizhiyong
     * @date 2019/4/2 20:03
     * @param dto 参数对象
     */
    String getQQAuthUrl(ThirdLoginDTO dto);

    /**
     * 通过应用类型+当前登录人ID查询中间表,展示微信&&QQ绑定情况
     *
     * @author quyuantao
     * @date 2019/4/2 20:04
     * @param thirdLogin 参数对象
     */
    Map<String, Object> thirdPartyBinding(ThirdLogin thirdLogin) throws Exception;

    /**
     * 绑定微信，通过code和appType获取其他数据，state用于校验有效期
     *
     * @author quyuantao
     * @date 2019/4/2 20:05
     * @param state 校验过期参数
     * @param code 临时票据
     * @param appType 应用类型
     */
    JSONObject bindWx(String state, String code, String appType) throws Exception;

    /**
     * 绑定微信，传入需要的数据直接完成绑定
     *
     * @author quyuantao
     * @date 2019/4/7 16:54
     * @param unionId 微信号唯一标识
     * @param openId 微信号在该应用下唯一标识
     * @param appType 应用类型
     * @param platformType 平台类型
     * @param userId 用户id
     * @param corpId 账套
     */
    void bindWx(String unionId, String openId, String appType, String platformType, Long userId, Long corpId) throws Exception;

    /**
     * 绑定QQ,通过token获取其它数据并完成绑定
     *
     * @author cuizhiyong
     * @date 2019/4/2 20:05
     * @param dto 参数对象
     * @throws Exception 内部调用方法可能返回的异常
     */
    JSONObject bindQQ(ThirdLoginDTO dto) throws Exception;

    /**
     * 绑定QQ，通过传入数据直接完成绑定
     *
     * @author cuizhiyong
     * @date 2019/4/2 20:05
     * @param unionId QQ的唯一ID
     * @param openId 该应用下，每个用户的唯一ID
     * @param platformType 平台类型，QQ(QQ平台),WX(微信平台)
     * @param userId 用户ID
     * @throws Exception 内部调用方法可能返回的异常
     */
    void bindQQ(String unionId, String openId, String appType, String platformType, Long userId, Long corpId) throws Exception;

    /**
     * 校验state状态，根据Code获取QQ认证信息（access_token、refresh_token、openid和unionid等）
     *
     * @author cuizhiyong
     * @date 2019/4/2 20:06
     * @param code  授权令牌，Authorization Code
     * @param state client端的状态值
     * @param isLogin 判断调用方法的来源是否是登录接口
     * @throws BasicServiceException 请求腾讯信息接口可能发生的异常
     */
    JSONObject getQQAuthToken(String code, String state, boolean isLogin) throws BasicServiceException;

    /**
     * 根据token获取QQ认证信息
     *
     * @author cuizhiyong
     * @date 2019/4/2 20:07
     * @param token QQ认证的access_token
     * @throws BasicServiceException 请求腾讯信息接口可能发生的异常
     */
    JSONObject getQQAuthInfo(String token) throws BasicServiceException;

    /**
     * 校验state字符串，获取
     * access_token 接口调用凭证
     * expires_in 接口调用凭证超时时间
     * refresh_token 用户刷新access_token
     * openid 授权用户唯一标识，当前微信在子系统唯一标识
     * scope 用户授权的作用域，使用逗号（,）分隔
     * unionid 当前微信号在整个系统的唯一标识
     *
     * @author quyuantao
     * @date 2019/4/2 20:08
     * @param code  临时票据
     * @param state 校验过期字符串
     * @param appType 应用类型
     */
    JSONObject getWXAuthInfo(String code, String state, String appType) throws BasicServiceException;

    /**
     * 解绑第三方账号
     *
     * @author quyuantao
     * @date 2019/4/2 20:09
     * @param appType      应用类型
     * @param platformType 平台类型
     */
    void unBoundThirdParty(String appType, String platformType) throws Exception;

    /**
     * unionId+appType+platform获取用户
     *
     * @author cuizhiyong
     * @date 2019/4/2 20:11
     * @param appType  应用类型 (CRM -- 品牌商网站应用  marketing -- 营销助手  dms -- 渠道协同平台)
     * @param token  微信号或QQ号唯一标识
     * @param platform 平台类型 (QQ||WX)
     * @param wxSecAuth 是否微信避开二次授权请求标识
     */
    List<User> getUsersByUnionIdAndAppType(String appType, String token, String platform, boolean wxSecAuth) throws Exception;

    /**
     * 根据code和state获取token、unionid等信息并写入redis，返回redis的key构造的字符串
     *
     * @author cuizhiyong
     * @param code access code
     * @param state client状态
     * @param isLogin 判断调用方法的来源是否是登录接口
     * @date 2019/4/3 10:23
     */
    String getLoginRedirectParam(String code, String state, boolean isLogin);

    /**
     * 封装access_token、refresh_token、openID、unionID到Redis缓存
     *
     * @author quyuantao
     * @date 2019/4/3 10:25
     * @param code 临时票据
     * @param state 校验过期字符串
     * @param appType 应用类型
     */
    String getWXRandomToken(String code, String state, String appType) throws Exception;

    /**
     * 移动端保存access_token、refesh_token等信息到redis缓存
     *
     * @author quyuantao
     * @date 2019/4/7 20:47
     * @param unionId 微信或QQ唯一标识
     * @param openId 微信或QQ在当前应用的唯一标识
     * @param accessToken 接口调用凭证
     * @param refreshToken 刷新accessToken凭证
     * @param platformType 平台类型 (QQ||WX)
     */
    void saveThirdInfo(String unionId, String openId, String accessToken, String refreshToken, String platformType);

    /**
     * 微信避免二次授权
     *
     * @author quyuantao
     * @date 2019/4/8 14:31
     * @param unionId 微信号唯一标识
     * @param openId 微信号在该应用的唯一标识
     * @param accessToken 接口调用凭证
     * @param appType 应用类型
     */
    boolean wxSecAuth(String unionId, String openId, String accessToken, String appType);

    /**
     * 通过redisKey获取缓存在redis里的认证信息
     *
     * @author quyuantao
     * @date 2019/4/11 11:37
     * @param token redis里的key值
     */
    Map<String, String> getAuthInfoFromRedis(String token);

    /**
     * 校验access_token是否有效
     *
     * @author quyuantao
     * @date 2019/4/11 15:32
     * @param accessToken 调用接口凭证
     * @param openId 微信在当前应用的唯一标识
     */
    boolean wxAuthAccessToken(String accessToken, String openId);

    /**
     * 刷新access_token
     *
     * @author quyuantao
     * @date 2019/4/11 15:39
     * @param refreshToken 用户刷新access_token凭证
     * @param appId 应用唯一标识
     */
    JSONObject wxRefreshAccessToken(String appId, String refreshToken);

    /**
     * 第三方权限控制
     *
     * @author quyuantao
     * @date 2019/6/14 17:10
     * @param platformTypeArr 平台类型 (QQ||WX)
     */
    Map<String, Object> authControl(String... platformTypeArr);
}
